package main

import (
	"errors"
	"github.com/google/cel-go/cel"
	"github.com/google/cel-go/checker/decls"
	"github.com/google/cel-go/common/types/ref"
	"golang.org/x/sync/errgroup"
	"log"
)

func Pcelgo(c int) {
	params := createParams()

	env, err := cel.NewEnv(
		cel.Declarations(
			decls.NewIdent("Origin", decls.String, nil),
			decls.NewIdent("Country", decls.String, nil),
			decls.NewIdent("Value", decls.Int, nil),
			decls.NewIdent("Adults", decls.Int, nil),
		),
	)
	if err != nil {
		log.Fatal(err)
	}

	parsed, issues := env.Parse(example)
	if issues != nil && issues.Err() != nil {
		log.Fatalf("parse error: %s", issues.Err())
	}
	checked, issues := env.Check(parsed)
	if issues != nil && issues.Err() != nil {
		log.Fatalf("type-check error: %s", issues.Err())
	}
	prg, err := env.Program(checked)
	if err != nil {
		log.Fatalf("program construction error: %s", err)
	}

	var out ref.Val

	for n := 0; n < c; n++ {
		out, _, err = prg.Eval(params)
	}

	if err != nil {
		log.Fatal(err)
	}
	if !out.Value().(bool) {
		log.Println("result error")
	}
}

func CelOne() error {
	params := createParams()

	env, err := cel.NewEnv(
		cel.Declarations(
			decls.NewIdent("Origin", decls.String, nil),
			decls.NewIdent("Country", decls.String, nil),
			decls.NewIdent("Value", decls.Int, nil),
			decls.NewIdent("Adults", decls.Int, nil),
		),
	)
	if err != nil {
		log.Println(err)
		return err
	}

	parsed, issues := env.Parse(example)
	if issues != nil && issues.Err() != nil {
		log.Printf("parse error: %s\n", issues.Err())
		return issues.Err()
	}
	checked, issues := env.Check(parsed)
	if issues != nil && issues.Err() != nil {
		log.Printf("type-check error: %s\n", issues.Err())
		return issues.Err()
	}
	prg, err := env.Program(checked)
	if err != nil {
		log.Printf("program construction error: %s", err)
		return err
	}

	var out ref.Val

	out, _, err = prg.Eval(params)

	if err != nil {
		log.Println(err)
		return err
	}
	if !out.Value().(bool) {
		log.Println("result error")
		return errors.New("result error")
	}
	return nil
}

func BatchCel(c int) {
	g := new(errgroup.Group)

	for n := 0; n < c; n++ {
		g.Go(func() error {
			err := CelOne()
			return err
		})
	}
	if err := g.Wait(); err != nil {
		log.Println("Get errors: ", err)
	} else {
		log.Println("Get all num successfully!")
	}
}

func Pcelgo_startswith(c int) {
	params := map[string]interface{}{
		"name":  "/groups/foo/bar",
		"group": "foo",
	}

	env, err := cel.NewEnv(
		cel.Declarations(
			decls.NewIdent("name", decls.String, nil),
			decls.NewIdent("group", decls.String, nil),
		),
	)
	if err != nil {
		log.Fatal(err)
	}

	parsed, issues := env.Parse(`name.startsWith("/groups/" + group)`)
	if issues != nil && issues.Err() != nil {
		log.Fatalf("parse error: %s", issues.Err())
	}
	checked, issues := env.Check(parsed)
	if issues != nil && issues.Err() != nil {
		log.Fatalf("type-check error: %s", issues.Err())
	}
	prg, err := env.Program(checked)
	if err != nil {
		log.Fatalf("program construction error: %s", err)
	}

	var out ref.Val

	for n := 0; n < c; n++ {
		out, _, err = prg.Eval(params)
	}

	if err != nil {
		log.Fatal(err)
	}
	if !out.Value().(bool) {
		log.Println("result error")
	}
}
